home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Text / Show / Less / less-252 / doscreen.c < prev    next >
C/C++ Source or Header  |  1994-10-15  |  11KB  |  572 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Routines which deal with the characteristics of the terminal.
  30.  *
  31.  * This file is specific to MS-DOS and uses Microsoft C graphics functions.
  32.  */
  33.  
  34. #include "less.h"
  35. #include "cmd.h"
  36.  
  37. #include <graph.h>
  38. #include <time.h>
  39.  
  40. static int init_done = 0;
  41. static int videopages;
  42. static long msec_loops;
  43.  
  44. public int auto_wrap;        /* Terminal does \r\n when write past margin */
  45. public int ignaw;        /* Terminal ignores \n immediately after wrap */
  46. public int erase_char, kill_char; /* The user's erase and line-kill chars */
  47. public int sc_width, sc_height;    /* Height & width of screen */
  48. public int bo_s_width, bo_e_width;    /* Printing width of boldface seq */
  49. public int ul_s_width, ul_e_width;    /* Printing width of underline seq */
  50. public int so_s_width, so_e_width;    /* Printing width of standout seq */
  51. public int bl_s_width, bl_e_width;    /* Printing width of blink seq */
  52.  
  53. public int nm_fg_color = 7;            /* Color of normal text */
  54. public int nm_bg_color = 0;
  55. public int bo_fg_color = 15;        /* Color of bold text */
  56. public int bo_bg_color = 0;
  57. public int ul_fg_color = 9;            /* Color of underlined text */
  58. public int ul_bg_color = 0;
  59. public int so_fg_color = 0;            /* Color of standout text */
  60. public int so_bg_color = 7;
  61. public int bl_fg_color = 12;        /* Color of blinking text */
  62. public int bl_bg_color = 0;
  63.  
  64. static int sy_fg_color;
  65. static int sy_bg_color;
  66. static int flash_created = 0;
  67.  
  68. extern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  69. extern int know_dumb;        /* Don't complain about a dumb terminal */
  70. extern int back_scroll;
  71. extern int swindow;
  72. extern char *getenv();
  73.  
  74. /*
  75.  * Change terminal to "raw mode", or restore to "normal" mode.
  76.  * "Raw mode" means 
  77.  *    1. An outstanding read will complete on receipt of a single keystroke.
  78.  *    2. Input is not echoed.  
  79.  *    3. On output, \n is mapped to \r\n.
  80.  *    4. \t is NOT expanded into spaces.
  81.  *    5. Signal-causing characters such as ctrl-C (interrupt),
  82.  *       etc. are NOT disabled.
  83.  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  84.  */
  85.     public void
  86. raw_mode(on)
  87.     int on;
  88. {
  89.     static int curr_on = 0;
  90.  
  91.     if (on == curr_on)
  92.         return;
  93.     erase_char = CONTROL('h');
  94.     kill_char = '\33'; /* ESC */
  95.     curr_on = on;
  96. }
  97.  
  98. /*
  99.  * Get size of the output screen.
  100.  */
  101.     public void
  102. scrsize(p_height, p_width)
  103.     int *p_height;
  104.     int *p_width;
  105. {
  106.     register char *s;
  107.     struct videoconfig w;
  108.  
  109.     _getvideoconfig(&w);
  110.  
  111.     if (w.numtextrows)
  112.         *p_height = w.numtextrows;
  113.     else if ((s = getenv("LINES")) != NULL && *s != '\0')
  114.         *p_height = atoi(s);
  115.     if (*p_height <= 0)
  116.         *p_height = 24;
  117.         
  118.     if (w.numtextcols > 0)
  119.         *p_width = w.numtextcols;
  120.     else if ((s = getenv("COLUMNS")) != NULL)
  121.         *p_width = atoi(s);
  122.     if (*p_width <= 0)
  123.           *p_width = 80;
  124. }
  125.  
  126. /*
  127.  * Figure out how many empty loops it takes to delay a millisecond.
  128.  */
  129.     static void
  130. get_clock()
  131. {
  132.     clock_t start;
  133.     
  134.     /*
  135.      * Get synchronized at the start of a tick.
  136.      */
  137.     start = clock();
  138.     while (clock() == start)
  139.         ;
  140.     /*
  141.      * Now count loops till the next tick.
  142.      */
  143.     start = clock();
  144.     msec_loops = 0;
  145.     while (clock() == start)
  146.         msec_loops++;
  147.     /*
  148.      * Convert from (loops per clock) to (loops per millisecond).
  149.      */
  150.     msec_loops *= CLOCKS_PER_SEC;
  151.     msec_loops /= 1000;
  152. }
  153.  
  154.     public void
  155. get_editkeys()
  156. {
  157. }
  158.  
  159. /*
  160.  * Get terminal capabilities via termcap.
  161.  */
  162.     public void
  163. get_term()
  164. {
  165.     scrsize(&sc_height, &sc_width);
  166.     pos_init();
  167.     auto_wrap = 1;
  168.     ignaw = 0;
  169.     so_e_width = so_s_width = 0;
  170.     bo_s_width = bo_e_width = 0;
  171.     ul_s_width = ul_e_width = 0;
  172.     bl_s_width = bl_e_width = 0;
  173.     get_clock();
  174. }
  175.  
  176.  
  177. /*
  178.  * Below are the functions which perform all the 
  179.  * terminal-specific screen manipulation.
  180.  */
  181.  
  182.  
  183. /*
  184.  * Initialize terminal
  185.  */
  186.     public void
  187. init()
  188. {
  189.     /* {{ What could we take no_init (-X) to mean? }} */
  190.     sy_bg_color = _getbkcolor();
  191.     sy_fg_color = _gettextcolor();
  192.     flush();
  193.     init_done = 1;
  194. }
  195.  
  196. /*
  197.  * Create an alternate screen which is all white.
  198.  * This screen is used to create a "flash" effect, by displaying it
  199.  * briefly and then switching back to the normal screen.
  200.  * {{ Yuck!  There must be a better way to get a visual bell. }}
  201.  */
  202.     static void
  203. create_flash()
  204. {
  205.     struct videoconfig w;
  206.     char *blanks;
  207.     int row, col;
  208.     
  209.     _getvideoconfig(&w);
  210.     videopages = w.numvideopages;
  211.     if (videopages < 2)
  212.     {
  213.         so_enter();
  214.         so_exit();
  215.     } else
  216.     {
  217.         _setactivepage(1);
  218.         so_enter();
  219.         blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
  220.         for (col = 0;  col < w.numtextcols;  col++)
  221.             blanks[col] = ' ';
  222.         for (row = w.numtextrows;  row > 0;  row--)
  223.             _outmem(blanks, w.numtextcols);
  224.         _setactivepage(0);
  225.         _setvisualpage(0);
  226.         free(blanks);
  227.         so_exit();
  228.     }
  229.     flash_created = 1;
  230. }
  231.  
  232. /*
  233.  * Deinitialize terminal
  234.  */
  235.     public void
  236. deinit()
  237. {
  238.     if (!init_done)
  239.         return;
  240.     _setbkcolor(sy_bg_color);
  241.     _settextcolor(sy_fg_color);
  242.     putstr("\n");
  243.     init_done = 0;
  244. }
  245.  
  246. /*
  247.  * Home cursor (move to upper left corner of screen).
  248.  */
  249.     public void
  250. home()
  251. {
  252.     flush();
  253.     _settextposition(1,1);
  254. }
  255.  
  256. /*
  257.  * Add a blank line (called with cursor at home).
  258.  * Should scroll the display down.
  259.  */
  260.     public void
  261. add_line()
  262. {
  263.     flush();
  264.     _scrolltextwindow(_GSCROLLDOWN);
  265.     _settextposition(1,1);
  266. }
  267.  
  268. /*
  269.  * Move cursor to lower left corner of screen.
  270.  */
  271.     public void
  272. lower_left()
  273. {
  274.     flush();
  275.     _settextposition(sc_height,1);
  276. }
  277.  
  278. /*
  279.  * Delay for a specified number of milliseconds.
  280.  */
  281.     static void
  282. dummy_func()
  283. {
  284.     static long delay_dummy = 0;
  285.     delay_dummy++;
  286. }
  287.  
  288.     static void
  289. delay(msec)
  290.     int msec;
  291. {
  292.     long i;
  293.     
  294.     while (msec-- > 0)
  295.     {
  296.         for (i = 0;  i < msec_loops;  i++)
  297.         {
  298.             /*
  299.              * Make it look like we're doing something here,
  300.              * so the optimizer doesn't remove the whole loop.
  301.              */
  302.             dummy_func();
  303.         }
  304.     }
  305. }
  306.  
  307. /*
  308.  * Make a noise.
  309.  */
  310.     static void
  311. beep()
  312. {
  313.     write(1, "\7", 1);
  314. }
  315.  
  316. /*
  317.  * Output the "visual bell", if there is one.
  318.  */
  319.     public void
  320. vbell()
  321. {
  322.     if (!flash_created)
  323.         /*
  324.          * Create a "flash" on the second video page.
  325.          */
  326.         create_flash();
  327.     if (videopages < 2)
  328.         /*
  329.          * There is no "second video page".
  330.          */
  331.         return;
  332.     _setvisualpage(1);
  333.     /*
  334.      * Leave it displayed for 100 msec.
  335.      */
  336.     delay(100);
  337.     _setvisualpage(0);
  338. }
  339.  
  340. /*
  341.  * Ring the terminal bell.
  342.  */
  343.     public void
  344. bell()
  345. {
  346.     if (quiet == VERY_QUIET)
  347.         vbell();
  348.     else
  349.         beep();
  350. }
  351.  
  352. /*
  353.  * Clear the screen.
  354.  */
  355.     public void
  356. clear()
  357. {
  358.     flush();
  359.     _clearscreen(_GCLEARSCREEN);
  360. }
  361.  
  362. /*
  363.  * Clear from the cursor to the end of the cursor's line.
  364.  * {{ This must not move the cursor. }}
  365.  */
  366.     public void
  367. clear_eol()
  368. {
  369.     short top, left;
  370.     short bot, right;
  371.     struct rccoord tpos;
  372.     
  373.     flush();
  374.     /*
  375.      * Save current state.
  376.      */
  377.     tpos = _gettextposition();
  378.     _gettextwindow(&top, &left, &bot, &right);
  379.     /*
  380.      * Set a temporary window to the current line,
  381.      * from the cursor's position to the right edge of the screen.
  382.      * Then clear that window.
  383.      */
  384.     _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
  385.     _clearscreen(_GWINDOW);
  386.     /*
  387.      * Restore state.
  388.      */
  389.     _settextwindow(top, left, bot, right);
  390.     _settextposition(tpos.row, tpos.col);
  391. }
  392.  
  393. /*
  394.  * Clear the bottom line of the display.
  395.  * Leave the cursor at the beginning of the bottom line.
  396.  */
  397.     public void
  398. clear_bot()
  399. {
  400.     lower_left();
  401.     clear_eol();
  402. }
  403.  
  404. /*
  405.  * Begin "standout" (bold, underline, or whatever).
  406.  */
  407.     public void
  408. so_enter()
  409. {
  410.     flush();
  411.     _setbkcolor(so_bg_color);
  412.     _settextcolor(so_fg_color);
  413. }
  414.  
  415. /*
  416.  * End "standout".
  417.  */
  418.     public void
  419. so_exit()
  420. {
  421.     flush();
  422.     _setbkcolor(nm_bg_color);
  423.     _settextcolor(nm_fg_color);
  424. }
  425.  
  426. /*
  427.  * Begin "underline" (hopefully real underlining, 
  428.  * otherwise whatever the terminal provides).
  429.  */
  430.     public void
  431. ul_enter()
  432. {
  433.     flush();
  434.     _setbkcolor(ul_bg_color);
  435.     _settextcolor(ul_fg_color);
  436. }
  437.  
  438. /*
  439.  * End "underline".
  440.  */
  441.     public void
  442. ul_exit()
  443. {
  444.     flush();
  445.     _setbkcolor(nm_bg_color);
  446.     _settextcolor(nm_fg_color);
  447. }
  448.  
  449. /*
  450.  * Begin "bold"
  451.  */
  452.     public void
  453. bo_enter()
  454. {
  455.     flush();
  456.     _setbkcolor(bo_bg_color);
  457.     _settextcolor(bo_fg_color);
  458. }
  459.  
  460. /*
  461.  * End "bold".
  462.  */
  463.     public void
  464. bo_exit()
  465. {
  466.     flush();
  467.     _setbkcolor(nm_bg_color);
  468.     _settextcolor(nm_fg_color);
  469. }
  470.  
  471. /*
  472.  * Begin "blink"
  473.  */
  474.     public void
  475. bl_enter()
  476. {
  477.     flush();
  478.     _setbkcolor(bl_bg_color);
  479.     _settextcolor(bl_fg_color);
  480. }
  481.  
  482. /*
  483.  * End "blink".
  484.  */
  485.     public void
  486. bl_exit()
  487. {
  488.     flush();
  489.     _setbkcolor(nm_bg_color);
  490.     _settextcolor(nm_fg_color);
  491. }
  492.  
  493. /*
  494.  * Erase the character to the left of the cursor 
  495.  * and move the cursor left.
  496.  */
  497.     public void
  498. backspace()
  499. {
  500.     struct rccoord tpos;
  501.     
  502.     /* 
  503.      * Erase the previous character by overstriking with a space.
  504.      */
  505.     flush();
  506.     tpos = _gettextposition();
  507.     if (tpos.col <= 1)
  508.         return;
  509.     _settextposition(tpos.row, tpos.col-1);
  510.     _outtext(" ");
  511.     _settextposition(tpos.row, tpos.col-1);
  512. }
  513.  
  514. /*
  515.  * Output a plain backspace, without erasing the previous char.
  516.  */
  517.     public void
  518. putbs()
  519. {
  520.     struct rccoord tpos;
  521.     
  522.     flush();
  523.     tpos = _gettextposition();
  524.     if (tpos.col <= 1)
  525.         return;
  526.     _settextposition(tpos.row, tpos.col-1);
  527. }
  528.  
  529. /*
  530.  * Table of line editting characters, for editchar() in decode.c.
  531.  */
  532. char edittable[] = {
  533.     '\340','\115',0,    EC_RIGHT,    /* RIGHTARROW */
  534.     '\340','\113',0,    EC_LEFT,    /* LEFTARROW */
  535.     '\340','\163',0,    EC_W_LEFT,    /* CTRL-LEFTARROW */
  536.     '\340','\164',0,    EC_W_RIGHT,    /* CTRL-RIGHTARROW */
  537.     '\340','\122',0,    EC_INSERT,    /* INSERT */
  538.     '\340','\123',0,    EC_DELETE,    /* DELETE */
  539.     '\340','\223',0,    EC_W_DELETE,    /* CTRL-DELETE */
  540.     '\177',0,        EC_W_BACKSPACE,    /* CTRL-BACKSPACE */
  541.     '\340','\107',0,    EC_HOME,    /* HOME */
  542.     '\340','\117',0,    EC_END,        /* END */
  543.     '\340','\110',0,    EC_UP,        /* UPARROW */
  544.     '\340','\120',0,    EC_DOWN,    /* DOWNARROW */
  545.     '\t',0,            EC_F_COMPLETE,    /* TAB */
  546.     '\17',0,        EC_B_COMPLETE,    /* BACKTAB (?) */
  547.     '\340','\17',0,        EC_B_COMPLETE,    /* BACKTAB */
  548.     '\14',0,        EC_EXPAND,    /* CTRL-L */
  549.     0  /* Extra byte to terminate; subtracted from size, below */
  550. };
  551.  
  552. int sz_edittable = sizeof(edittable) -1;
  553.  
  554.  
  555. char kcmdtable[] =
  556. {
  557.     /*
  558.      * PC function keys.
  559.      * Note that '\0' is converted to '\340' on input.
  560.      */
  561.     '\340','\120',0,        A_F_LINE,        /* down arrow */
  562.     '\340','\121',0,        A_F_SCREEN,        /* page down */
  563.     '\340','\110',0,        A_B_LINE,        /* up arrow */
  564.     '\340','\111',0,        A_B_SCREEN,        /* page up */
  565.     '\340','\107',0,        A_GOLINE,        /* home */
  566.     '\340','\117',0,        A_GOEND,        /* end */
  567.     '\340','\073',0,        A_HELP,            /* F1 */
  568.     '\340','\022',0,        A_EXAMINE,        /* Alt-E */
  569.     0
  570. };
  571. int sz_kcmdtable = sizeof(kcmdtable) - 1;
  572.